import React from 'react';
import { useEditor, EditorContent, BubbleMenu, Editor, Extension } from '@tiptap/react';
import { Plugin } from 'prosemirror-state';
import { TextSelection } from 'prosemirror-state';
import StarterKit from '@tiptap/starter-kit';
import Highlight from '@tiptap/extension-highlight';
import Typography from '@tiptap/extension-typography';
import Placeholder from '@tiptap/extension-placeholder';
import TextStyle from '@tiptap/extension-text-style';
import Color from '@tiptap/extension-color';
import Underline from '@tiptap/extension-underline';
import TextAlign from '@tiptap/extension-text-align';
import Link from '@tiptap/extension-link';
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
import { common, createLowlight } from 'lowlight';
import { Node as ProseMirrorNode } from '@tiptap/pm/model';
import { mergeAttributes } from '@tiptap/core';
import Paragraph from '@tiptap/extension-paragraph';
import 'remixicon/fonts/remixicon.css';
import './index.less';

const lowlight = createLowlight(common);

interface NodeViewProps {
  node: ProseMirrorNode;
  HTMLAttributes: Record<string, any>;
}

// 自定义段落扩展
const CustomParagraph = Paragraph.extend({
  name: 'paragraph',

  addOptions() {
    return {
      HTMLAttributes: {
        class: 'notion-paragraph',
      },
    };
  },

  addNodeView() {
    return ({ node, HTMLAttributes, editor, getPos }) => {
      const dom = document.createElement('div');
      dom.classList.add('notion-paragraph-wrapper');

      const addButton = document.createElement('button');
      addButton.classList.add('add-paragraph-btn');
      addButton.innerHTML = '<i class="ri-add-line"></i>';
      addButton.title = '添加段落';

      const dragHandle = document.createElement('button');
      dragHandle.classList.add('drag-handle');
      dragHandle.innerHTML = '<i class="ri-drag-move-line"></i>';
      dragHandle.title = '拖动排序';

      // 拖拽相关事件处理
      let isDragging = false;
      let dragImage: HTMLElement | null = null;

      // 使用更可靠的方法获取段落位置
      const getReliablePosition = (editor: Editor, domElement: HTMLElement) => {
        try {
          // 1. 首先尝试通过DOM元素直接获取位置
          const contentElement = domElement.querySelector('.notion-paragraph');
          if (!contentElement) return -1;
          
          // 2. 使用resolvePosition方法
          const resolvedPos = editor.view.posAtDOM(contentElement, 0);
          console.log('resolvedPos:', resolvedPos);
          
          // 3. 验证位置是否有效
          if (resolvedPos >= 0 && resolvedPos <= editor.state.doc.content.size) {
            // 确认这个位置确实是一个段落节点
            const $pos = editor.state.doc.resolve(resolvedPos);
            const node = $pos.node(1); // 获取父节点
            
            if (node && node.type.name === 'paragraph') {
              return resolvedPos;
            }
          }
          
          // 4. 如果上述方法失败，尝试遍历所有段落找到匹配的DOM
          let foundPos = -1;
          
          // 获取所有段落DOM元素
          const allParagraphs = Array.from(editor.view.dom.querySelectorAll('.notion-paragraph-wrapper'));
          const index = allParagraphs.indexOf(domElement);
          
          if (index !== -1) {
            // 找到了元素的索引，现在遍历文档找到对应的段落
            let paragraphCount = 0;
            
            editor.state.doc.descendants((node, pos) => {
              if (foundPos !== -1) return false; // 已找到，停止遍历
              
              if (node.type.name === 'paragraph') {
                if (paragraphCount === index) {
                  foundPos = pos;
                  return false;
                }
                paragraphCount++;
              }
              
              return true;
            });
            
            if (foundPos !== -1) {
              console.log('通过索引找到位置:', foundPos);
              return foundPos;
            }
          }
          
          // 5. 最后的尝试：使用当前选择位置
          const { from } = editor.state.selection;
          const $from = editor.state.doc.resolve(from);
          
          if ($from.parent.type.name === 'paragraph') {
            console.log('使用当前选择位置:', $from.before(1));
            return $from.before(1);
          }
          
          return -1;
        } catch (error) {
          console.error('获取位置时出错:', error);
          return -1;
        }
      };

      const handleDragHandleMouseDown = (e: MouseEvent) => {
        // 只处理左键点击
        if (e.button !== 0) return;

        console.log('handleDragHandleMouseDown');
        isDragging = true;
        dom.setAttribute('draggable', 'true');

        // 等待下一帧再创建拖拽图像，确保DOM已经渲染
        requestAnimationFrame(() => {
          // 创建拖拽图像
          dragImage = dom.cloneNode(true) as HTMLElement;
          
          // 先将元素添加到 .ant-app 中但设置为不可见
          dragImage.style.visibility = 'hidden';
          const antApp = document.querySelector('.ant-app');
          if (!antApp) return;
          antApp.appendChild(dragImage);
          
          // 删除克隆元素中的按钮
          const addBtn = dragImage.querySelector('.add-paragraph-btn');
          const dragBtn = dragImage.querySelector('.drag-handle');
          if (addBtn) addBtn.remove();
          if (dragBtn) dragBtn.remove();
          
          // 获取实际尺寸
          const width = dragImage.offsetWidth || dom.getBoundingClientRect().width;
          const height = dragImage.offsetHeight || dom.getBoundingClientRect().height;
          
          // 设置拖拽图像的特殊样式（只覆盖必要的属性）
          Object.assign(dragImage.style, {
            position: 'fixed',
            pointerEvents: 'none',
            zIndex: '99999',
            width: `${width}px`,
            height: `${height}px`,
            left: `${e.clientX}px`,
            top: `${e.clientY}px`,
            transform: 'translate(-20px, -50%)',
            visibility: 'visible',
            WebkitMaskImage: 'linear-gradient(to right, rgba(0,0,0,0.8) 50px, rgba(0,0,0,0) 450px)',
            maskImage: 'linear-gradient(to right, rgba(0,0,0,0.8) 50px, rgba(0,0,0,0) 450px)',
          });

          // 移除旧的拖拽图像（如果存在）
          const oldDragImage = document.querySelector('.drag-image-clone');
          if (oldDragImage) {
            oldDragImage.remove();
          }

          // 添加特殊类名以便识别
          dragImage.classList.add('drag-image-clone');
          // 获取源位置
          const sourcePos = getReliablePosition(editor, dom);
          console.log('Source position:', sourcePos);
          if (sourcePos === -1) {
            console.log('无法获取有效位置，仅清理状态');
            // 清理拖拽状态
            editor.view.dom.classList.remove('dragging-active');
            (editor.view.dom as HTMLElement).removeAttribute('data-dragging');
            (editor.view.dom as HTMLElement).removeAttribute('data-drag-source');
            dom.classList.remove('is-dragging');
            
            // 清除所有段落的拖拽状态
            const allParagraphs = editor.view.dom.querySelectorAll('.notion-paragraph-wrapper');
            allParagraphs.forEach(p => {
              p.classList.remove('drag-over-top', 'drag-over-bottom');
            });
            
            return;
          }

          // 设置拖拽状态
          editor.view.dom.classList.add('dragging-active');
          (editor.view.dom as HTMLElement).setAttribute('data-dragging', 'true');
          (editor.view.dom as HTMLElement).setAttribute('data-drag-source', sourcePos.toString());
          dom.classList.add('is-dragging');

          // 阻止文本选择
          e.preventDefault();

          // 添加鼠标移动和抬起事件监听器
          const handleMouseMove = (e: MouseEvent) => {
            if (!isDragging || !dragImage) return;
            
            // 更新拖拽图像位置
            dragImage.style.left = `${e.clientX}px`;
            dragImage.style.top = `${e.clientY}px`;

            // 处理拖拽悬停效果
            const elemBelow = document.elementFromPoint(e.clientX, e.clientY);
            const paragraphBelow = elemBelow?.closest('.notion-paragraph-wrapper') as HTMLElement;
            
            if (paragraphBelow && paragraphBelow !== dom) {
              // 清除其他段落的状态
              const allParagraphs = editor.view.dom.querySelectorAll('.notion-paragraph-wrapper');
              allParagraphs.forEach(p => {
                if (p !== paragraphBelow) {
                  p.classList.remove('drag-over-top', 'drag-over-bottom');
                }
              });

              // 设置当前段落的状态
              const rect = paragraphBelow.getBoundingClientRect();
              const midPoint = rect.top + rect.height / 2;

              if (e.clientY < midPoint) {
                paragraphBelow.classList.remove('drag-over-bottom');
                paragraphBelow.classList.add('drag-over-top');
              } else {
                paragraphBelow.classList.remove('drag-over-top');
                paragraphBelow.classList.add('drag-over-bottom');
              }
            }
          };

          const handleGlobalMouseUp = (e: MouseEvent) => {
            console.log('handleGlobalMouseUp');
            isDragging = false;
            dom.setAttribute('draggable', 'false');

            // 移除拖拽图像
            const antApp = document.querySelector('.ant-app');
            if (dragImage && antApp?.contains(dragImage)) {
              antApp.removeChild(dragImage);
            }
            dragImage = null;

            // 获取源位置
            const sourcePos = getReliablePosition(editor, dom);
            if (sourcePos === -1) {
              console.log('Invalid source position, cleaning up only');
              // 清理拖拽状态
              editor.view.dom.classList.remove('dragging-active');
              (editor.view.dom as HTMLElement).removeAttribute('data-dragging');
              (editor.view.dom as HTMLElement).removeAttribute('data-drag-source');
              dom.classList.remove('is-dragging');
              
              // 清除所有段落的拖拽状态
              const allParagraphs = editor.view.dom.querySelectorAll('.notion-paragraph-wrapper');
              allParagraphs.forEach(p => {
                p.classList.remove('drag-over-top', 'drag-over-bottom');
              });
              
              return;
            }

            // 找到鼠标下方的段落
            const elemBelow = document.elementFromPoint(e.clientX, e.clientY);
            const targetWrapper = elemBelow?.closest('.notion-paragraph-wrapper');
            
            if (targetWrapper && targetWrapper !== dom) {
              // 找到目标段落的位置
              const targetContent = targetWrapper.querySelector('.notion-paragraph');
              if (!targetContent) return;
              
              // 获取目标位置
              const targetPos = editor.view.posAtDOM(targetContent, 0);
              const targetRect = targetWrapper.getBoundingClientRect();
              const midPoint = targetRect.top + targetRect.height / 2;
              
              // 确定是放在目标段落前面还是后面
              let finalTargetPos = targetPos;
              if (e.clientY > midPoint) {
                const targetNode = editor.view.state.doc.nodeAt(targetPos);
                if (targetNode) {
                  finalTargetPos = targetPos + targetNode.nodeSize;
                }
              }
              
              // 如果源位置和目标位置相同，不执行操作
              if (sourcePos === finalTargetPos) return;
              
              // 执行移动操作
              const tr = editor.view.state.tr;
              const sourceNode = editor.view.state.doc.nodeAt(sourcePos);
              if (!sourceNode) return;
              
              // 根据源位置和目标位置的关系调整删除和插入的顺序
              if (sourcePos < finalTargetPos) {
                tr.delete(sourcePos, sourcePos + sourceNode.nodeSize)
                  .insert(finalTargetPos - sourceNode.nodeSize, sourceNode);
              } else {
                tr.delete(sourcePos, sourcePos + sourceNode.nodeSize)
                  .insert(finalTargetPos, sourceNode);
              }
              
              editor.view.dispatch(tr);
            }

            // 清理拖拽状态
            editor.view.dom.classList.remove('dragging-active');
            (editor.view.dom as HTMLElement).removeAttribute('data-dragging');
            (editor.view.dom as HTMLElement).removeAttribute('data-drag-source');
            dom.classList.remove('is-dragging');

            // 清除所有段落的拖拽状态
            const allParagraphs = editor.view.dom.querySelectorAll('.notion-paragraph-wrapper');
            allParagraphs.forEach(p => {
              p.classList.remove('drag-over-top', 'drag-over-bottom');
            });

            // 清理事件监听器
            window.removeEventListener('mousemove', handleMouseMove);
            window.removeEventListener('mouseup', handleGlobalMouseUp);
          };

          window.addEventListener('mousemove', handleMouseMove);
          window.addEventListener('mouseup', handleGlobalMouseUp);
        });
      };

      // 添加事件监听
      dragHandle.addEventListener('mousedown', handleDragHandleMouseDown);

      const content = document.createElement('p');
      Object.entries(HTMLAttributes || {}).forEach(([key, value]) => {
        content.setAttribute(key, value as string);
      });
      content.classList.add('notion-paragraph');

      dom.appendChild(addButton);
      dom.appendChild(dragHandle);
      dom.appendChild(content);

      // 添加段落按钮点击事件
      addButton.addEventListener('click', (e) => {
        e.preventDefault();
        e.stopPropagation();
        
        const pos = getReliablePosition(editor, dom);
        if (pos === -1) return;
        
        // 获取节点大小
        const nodeSize = editor.view.state.doc.nodeAt(pos)?.nodeSize || 2;
        
        // 在当前段落后创建新段落
        const tr = editor.state.tr;
        const newNode = editor.state.schema.nodes.paragraph.create(
          null,
          editor.state.schema.text('/')
        );
        tr.insert(pos + nodeSize, newNode);
        
        // 设置光标位置到斜杠后面
        const newPos = tr.doc.resolve(pos + nodeSize + 2);
        tr.setSelection(TextSelection.create(tr.doc, newPos.pos));
        
        editor.view.dispatch(tr);
        editor.view.focus();
      });

      return {
        dom,
        contentDOM: content,
        destroy: () => {
          dragHandle.removeEventListener('mousedown', handleDragHandleMouseDown);
          addButton.removeEventListener('click', () => {});
          // 确保清理拖拽图像
          if (dragImage && dragImage.parentNode) {
            dragImage.parentNode.removeChild(dragImage);
          }
        },
      };
    };
  },

  parseHTML() {
    return [{ tag: 'p' }];
  },

  renderHTML({ HTMLAttributes }) {
    return ['p', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
  },
});

// 自定义扩展，用于处理 Ctrl+Enter 换行
const CustomKeymap = Extension.create({
  name: 'customKeymap',

  addKeyboardShortcuts() {
    return {
      'Ctrl-Enter': () => {
        return this.editor.commands.setHardBreak();
      },
      'Enter': ({ editor }) => {
        const { state } = editor;
        const { selection } = state;
        const { empty, $from } = selection;

        // 如果在段落末尾按回车
        if (empty && $from.parent.type.name === 'paragraph' && $from.pos === $from.end()) {
          editor.commands.insertContent({ type: 'paragraph', content: [{ type: 'text', text: '/' }] });
          return true;
        }
        return false;
      },
    };
  },
});

const TipTap = () => {
  const editor = useEditor({
    extensions: [
      StarterKit.configure({
        paragraph: false,
      }),
      CustomParagraph,
      CustomKeymap,
      Highlight,
      Typography,
      Placeholder.configure({
        placeholder: '点击任意位置开始输入...',
      }),
      TextStyle,
      Color,
      Underline,
      TextAlign.configure({
        types: ['heading', 'paragraph'],
      }),
      Link.configure({
        openOnClick: false,
      }),
      CodeBlockLowlight.configure({
        lowlight,
      }),
    ],
    content: '<p>欢迎使用编辑器！</p>',
    editorProps: {
      attributes: {
        class: 'notion-style-editor',
      },
    },
  });

  return (
    <div className="editor-container">
      <div className="editor-content-wrapper">
        <EditorContent editor={editor} />
      </div>
      {editor && (
        <BubbleMenu editor={editor} tippyOptions={{ duration: 100 }}>
          <div className="bubble-menu-group">
            <button
              onClick={() => editor.chain().focus().toggleBold().run()}
              className={editor.isActive('bold') ? 'is-active' : ''}
              title="加粗"
            >
              <i className="ri-bold" />
            </button>
            <button
              onClick={() => editor.chain().focus().toggleItalic().run()}
              className={editor.isActive('italic') ? 'is-active' : ''}
              title="斜体"
            >
              <i className="ri-italic" />
            </button>
            <button
              onClick={() => editor.chain().focus().toggleStrike().run()}
              className={editor.isActive('strike') ? 'is-active' : ''}
              title="删除线"
            >
              <i className="ri-strikethrough" />
            </button>
            <button
              onClick={() => editor.chain().focus().toggleUnderline().run()}
              className={editor.isActive('underline') ? 'is-active' : ''}
              title="下划线"
            >
              <i className="ri-underline" />
            </button>
            <button
              onClick={() => editor.chain().focus().toggleHighlight().run()}
              className={editor.isActive('highlight') ? 'is-active' : ''}
              title="高亮"
            >
              <i className="ri-mark-pen-line" />
            </button>
            <button
              onClick={() => editor.chain().focus().toggleCode().run()}
              className={editor.isActive('code') ? 'is-active' : ''}
              title="行内代码"
            >
              <i className="ri-code-line" />
            </button>
            <button
              onClick={() => editor.chain().focus().setTextAlign('left').run()}
              className={editor.isActive({ textAlign: 'left' }) ? 'is-active' : ''}
              title="左对齐"
            >
              <i className="ri-align-left" />
            </button>
            <button
              onClick={() => editor.chain().focus().setTextAlign('center').run()}
              className={editor.isActive({ textAlign: 'center' }) ? 'is-active' : ''}
              title="居中对齐"
            >
              <i className="ri-align-center" />
            </button>
            <button
              onClick={() => editor.chain().focus().setTextAlign('right').run()}
              className={editor.isActive({ textAlign: 'right' }) ? 'is-active' : ''}
              title="右对齐"
            >
              <i className="ri-align-right" />
            </button>
          </div>
        </BubbleMenu>
      )}
    </div>
  );
};

export default TipTap;